package site.xuxingcan.voiceforwarder;

import android.content.ContentValues;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;

import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;

import static de.robv.android.xposed.XposedHelpers.callStaticMethod;
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
import static de.robv.android.xposed.XposedHelpers.findClass;

/**
 * Created by xuxingcan on 16-11-20.
 */

public class XposedInit implements IXposedHookLoadPackage {
    private Class<?> mModleClass;
    private Class<?> mModelVoiceF;
    private Class<?> mModelVoiceQ;
    private XReceiver mXReceiver;
    private Context mContext;
    private Class<?> mModelVoiceM;
    private Class<?> mModelMultiClassh;
    private Handler mHandler;
    private Class<?> mUserIdClass;

    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
        if (!loadPackageParam.packageName.contains("tencent.mm")) {
            return;
        }
        try {
            classInit(loadPackageParam.classLoader);
        } catch (Exception e) {
            XposedBridge.log(e);
        }
        try {
            hookDatabase(loadPackageParam.classLoader);
        } catch (Exception e) {
            XposedBridge.log(e);
        }
        try {
            hookLauncherUI(loadPackageParam.classLoader);
        } catch (Exception e) {
            XposedBridge.log(e);
        }
    }

    protected void hookDatabase(ClassLoader loader) {
        XposedHelpers.findAndHookMethod("com.tencent.kingkong.database.SQLiteDatabase", loader,
                "insertWithOnConflict", String.class, String.class, ContentValues.class, int.class, new XC_MethodHook() {
                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                        String s = (String) param.args[0];
                        if (!s.equalsIgnoreCase("message"))
                            return;
                        ContentValues v = (ContentValues) param.args[2];
                        for (String key : v.keySet()) {
                            Object object = v.get(key);
                            if (object == null) {
                                XposedBridge.log(key + " = null");
                            } else {
                                XposedBridge.log(key + " = " + object.toString());
                                XposedBridge.log(key + " class = " + object.getClass().getName());
                            }
                        }
                        final String talker = (String) v.get("talker");
                        String content = (String) v.get("content");
                        int isSend;
                        if (v.containsKey("isSend")) {
                            isSend = (int) v.get("isSend");
                        } else {
                            isSend = content.startsWith(getUserId()) ? 1 : 0;
                        }
                        int type = (int) v.get("type");
                        SettingModel settingModel = FileUtil.getInstance().getSettingModel();
                        if (settingModel.mForwardArrayList == null) {
                            settingModel.mForwardArrayList = new ArrayList<String>();
                        }
                        if (isSend == 1) {
                            if ("添加转发群".equals(content)) {
                                settingModel.mForwardArrayList.add(talker);
                                FileUtil.getInstance().writeSetting(settingModel);
                                if (mContext != null) {
                                    ToastHelper.Toast(mContext, "添加转发群成功");
                                }
                            } else if ("删除转发群".equals(content)) {
                                settingModel.mForwardArrayList.remove(talker);
                                FileUtil.getInstance().writeSetting(settingModel);
                                if (mContext != null) {
                                    ToastHelper.Toast(mContext, "删除转发群成功");
                                }
                            } else if ("清空转发群".equals(content)) {
                                settingModel.mForwardArrayList.clear();
                                FileUtil.getInstance().writeSetting(settingModel);
                                if (mContext != null) {
                                    ToastHelper.Toast(mContext, "清空转发群成功");
                                }
                            } else if ("设置语音来源".equals(content)) {
                                settingModel.fromId = talker;
                                FileUtil.getInstance().writeSetting(settingModel);
                                if (mContext != null) {
                                    ToastHelper.Toast(mContext, "设置语音来源成功");
                                }
                            } else if ("设置主群".equals(content)) {
                                settingModel.mainGroupId = talker;
                                FileUtil.getInstance().writeSetting(settingModel);
                                if (mContext != null) {
                                    ToastHelper.Toast(mContext, "设置主群成功");
                                }
                            }
                        } else {
                            if (talker.equals(settingModel.mainGroupId) && content.contains("家人们大家好")) {
                                settingModel.fromId = content.substring(0, content.indexOf(":"));
                                FileUtil.getInstance().writeSetting(settingModel);
//                                sendText(talker, "转播源已更换");
                            }
                        }
                        if (isSend != 1 && !TextUtils.isEmpty(content) && (/*talker.equals(settingModel.fromId) ||*/ content.startsWith(settingModel.fromId))) {
                            switch (type) {
                                case 1:
                                    break;
                                case 436207665:
                                    break;
                                case 34://语音
                                    String voicePath = (String) XposedHelpers.callStaticMethod(mModelVoiceQ, "hD", new Object[]{v.getAsString("imgPath")});
                                    int voiceTime = Integer.parseInt(content.split(":")[1]);
                                    for (String sendId : settingModel.mForwardArrayList) {
                                        if (talker.equals(sendId)) {
                                            continue;
                                        }
                                        String newVoiceNumber = (String) XposedHelpers.callStaticMethod(mModelVoiceQ, "jP", sendId);
                                        String imgPath = (String) XposedHelpers.callStaticMethod(mModelVoiceQ, "hD", new Object[]{newVoiceNumber});
                                        if (copyFile(new File(voicePath), new File(imgPath))) {
                                            XposedHelpers.callStaticMethod(mModelVoiceQ, "i", new Object[]{newVoiceNumber, voiceTime, 1});
                                            sendVoice(imgPath);
                                        }
                                    }
                                    if (mHandler == null) {
                                        mHandler = new Handler();
                                    }
                                    mHandler.removeCallbacksAndMessages(null);
                                    for (int i = 0; i < settingModel.mForwardArrayList.size(); i++) {
                                        mHandler.postDelayed(new Runnable() {
                                            @Override
                                            public void run() {
                                                XposedHelpers.callMethod(XposedHelpers.callStaticMethod(mModelVoiceM, "Ec"), "run");
                                            }
                                        }, (i + 1) * 2000L);
                                    }
                                    break;
                                case 3://图片
                                    String imgPath = (String) XposedHelpers.callStaticMethod(mModelVoiceQ, "hD", new Object[]{v.getAsString("imgPath")});
                                    XposedBridge.log("imgPath = " + imgPath);
                                    break;
                                case 62://小视频
                                    String videoPath = (String) XposedHelpers.callStaticMethod(mModelVoiceQ, "hD", new Object[]{v.getAsString("imgPath")});
                                    XposedBridge.log("videoPath = " + videoPath);
                                    break;
                            }
                        }
                    }
                });
    }

    public static boolean copyFile(final File rawFile, final File newFile) {
        try {
            if (!rawFile.exists()) {
                return false;
            }
            final BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(rawFile));
            final byte[] array = new byte[bufferedInputStream.available()];
            bufferedInputStream.read(array);
            bufferedInputStream.close();
            if (!newFile.exists()) {
                newFile.createNewFile();
            }
            final BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(newFile));
            bufferedOutputStream.write(array);
            bufferedOutputStream.flush();
            bufferedOutputStream.close();
            return true;
        } catch (Throwable t) {
            return false;
        }
    }

    public void sendVoice(String path) {
        XposedHelpers.callMethod(XposedHelpers.callStaticMethod(this.mModleClass, "ts"), "d", XposedHelpers.newInstance(this.mModelVoiceF, new Object[]{path}));
    }

    public void sendText(String to, String content) {
        XposedHelpers.callMethod(XposedHelpers.callStaticMethod(this.mModleClass, "ts"), "d", XposedHelpers.newInstance(this.mModelMultiClassh, new Object[]{to, content, 1}));
    }

    public String getUserId() {
        return (String) callStaticMethod(mUserIdClass, "rT");
    }

    private void classInit(ClassLoader loader) {
        mModleClass = findClass("com.tencent.mm.model.ah", loader);
        mModelVoiceF = findClass("com.tencent.mm.modelvoice.f", loader);
        mModelVoiceQ = findClass("com.tencent.mm.modelvoice.q", loader);
        mModelVoiceM = findClass("com.tencent.mm.modelvoice.m", loader);
        mModelMultiClassh = findClass("com.tencent.mm.modelmulti.h", loader);
        mUserIdClass = findClass("com.tencent.mm.model.h", loader);
    }

    private void hookLauncherUI(ClassLoader loader) {
        findAndHookMethod("com.tencent.mm.ui.LauncherUI", loader, "onCreate", Bundle.class, new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                super.afterHookedMethod(param);
                mContext = (Context) param.thisObject;
                mXReceiver = new XReceiver();
                mContext.registerReceiver(mXReceiver, XReceiver.getIntentFilter());
            }
        });
        findAndHookMethod("com.tencent.mm.ui.LauncherUI", loader, "onDestroy", new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                super.afterHookedMethod(param);
                Context mContext = (Context) param.thisObject;
                if (mXReceiver != null) {
                    mContext.unregisterReceiver(mXReceiver);
                }
            }
        });
    }
}
